import axios from 'axios'
import store from '@/store'
import router from '@/router'

const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API,
  // axios请求的完整地址: baseURL + url
  // 不能让axios直接去请求http://开头的外链地址, 而是要请求/开头还得命中本地开发服务器里代理规则
  // 知识点: 请求的路径问题
  // axios/script标签src/img标签的src/link的href. 都会发起一次请求
  // 如果是./开头的地址, 找当前文件夹
  // 如果是http开头的地址, 找到外链外部服务器(链接网络)
  // 如果是/开头的地址, 忽略文件夹, 直接找当前运行时, 所在服务器
  timeout: 5000
})

service.interceptors.request.use(
  config => {
    // 知识点: js文件中能否使用this.$store?
    // 不能, 因为这个this关键字不是Vue组件对象, 无法查找原型链上$store
    // 但是this.$store为了拿到的是store/index.js导出store对象
    // 解决: 我们直接把store对象导入过来使用, 是同一个store对象
    const token = store.getters.token
    if (token) {
      config.headers.Authorization = `Bearer ${token}`
    }
    return config
  },
  error => {
    return Promise.reject(error)
  }
)

// 响应拦截器
// 知识点1: axios内部的处理机制
// 方式1: http状态码处理:
// (1): http状态码为2xx, 3xx, 就会给Promise对象位置, 返回成功的结果(resolve())
// (2): http状态码为4xx, 5xx, 就会给Promise对象位置, 返回错误的结果(reject())
// 如果你想做一些操作, 你可以在axios的响应拦截器, 自己来处理返回的结果
// 补充: http状态码, 由本次请求后, 后端进行设置返回的
// 方式2: 后台返回的对象里code字段/success字段("逻辑字段"判断)
service.interceptors.response.use(
  response => { // http为2xx, 3xx进入这里
    // 本项目成功/失败都是2xx响应状态码, 都进入这里, 所以需要自己根据字段判定
    // 知识点2: axios内部会把后台返回的数据直接放到data字段下面(第一个data是axios处理的)
    const { success, message } = response.data
    if (success === false) { // 失败
      return Promise.reject(new Error(message))
    } else { // 成功
      // 返回response->返回的还是axios处理的结果对象(逻辑那边得.data.data)拿到后台返回值
      // 返回response.data->返回的就是后台返回的响应对象(逻辑那边拿到的真正的数据.data)拿到返回值
      return response.data // 特殊: 它返回到的是axios调用在原地留下的"Promise"对象位置(逻辑页面await 后面)
    }
  },
  error => { // http为4xx, 5xx进入这里
    // 身份过期, 后台双重返回401, 逻辑状态码
    // 前置非空判断(error有值, 才会执行&&后面的代码)
    // 确保error有值, 再.response, .reponse有值, 再.status
    // 防止null.xxxx 语法报错代码停止
    // if (error && error.response && error.response.status === 401) {
    //   // 身份过期, 删除所有cookie, 重置vuex, 强制回到登录页面
    // }
    // 但是账号密码失败的时候返回的是200, 用逻辑判断 - 最好统一
    // code更好, 因为401如果有多个情况, success只能判断是失败, 我们可以跟后台商量code值不同错误不同
    // 10000 成功  10002 身份过期  10004 xxxx
    if (error.response.data.code === 10002) { // 身份过期
      store.commit('user/RESET_STATE')
      store.commit('user/REMOVE_TOKEN') // 内部会删除本地cookie里token
      // router.currentRoute 路由对象内置的, 也拿到当前页面路由的信息对象
      router.replace(`/login?redirect=${encodeURIComponent(router.currentRoute.fullPath)}`)
    } // 效果: 手改/等2小时, 让本地cookie里token过期, 刷新网页会强制回到登录页面

    return Promise.reject(error) // 相当于reject(error)
  }
)

export default service
